
#pragma once
#include <cstdint>
#include <stdexcept>
#include <tuple>
#include <type_traits>
#include <cstring>
#include <functional>
#include <string>
namespace cc { namespace spell {
#ifndef MSVC_WORKAROUND
 struct OutOfRange { OutOfRange(unsigned , unsigned ) {} }; constexpr unsigned requires_in_range(unsigned i, unsigned len) { return i >= len ? throw OutOfRange(i, len) : i; }  class const_str { const char* const begin_; unsigned size_; public: template< unsigned N > constexpr const_str(const char(&arr)[N]) : begin_(arr), size_(N - 1) { static_assert(N >= 1, "not a string literal"); } constexpr char operator[](unsigned i) const { return requires_in_range(i, size_), begin_[i]; } constexpr operator const char* () const { return begin_; } constexpr const char* begin() const { return begin_; } constexpr const char* end() const { return begin_ + size_; } constexpr unsigned size() const { return size_; } }; constexpr unsigned find_closing_tag(const_str s, unsigned p) { return s[p] == '>' ? p : find_closing_tag(s, p + 1); } constexpr unsigned long long hack(const char* s) { unsigned long long r = 0; for (int i = 0; s[i]; r *= 0x100, r += s[i++]); return r; } constexpr bool is_valid(const_str s, unsigned i = 0, int f = 0) { return i == s.size() ? f == 0 : f < 0 || f >= 2 ? false : s[i] == '<' ? is_valid(s, i + 1, f + 1) : s[i] == '>' ? is_valid(s, i + 1, f - 1) : is_valid(s, i + 1, f); } constexpr bool is_equ_p(const char* a, const char* b, unsigned n) { return *a == 0 && *b == 0 && n == 0 ? true : (*a == 0 || *b == 0) ? false : n == 0 ? true : *a != *b ? false : is_equ_p(a + 1, b + 1, n - 1); } constexpr bool is_equ_n(const_str a, unsigned ai, const_str b, unsigned bi, unsigned n) { return ai + n > a.size() || bi + n > b.size() ? false : n == 0 ? true : a[ai] != b[bi] ? false : is_equ_n(a, ai + 1, b, bi + 1, n - 1); } constexpr bool is_int(const_str s, unsigned i) { return is_equ_n(s, i, "<int>", 0, 5); } constexpr bool is_uint(const_str s, unsigned i) { return is_equ_n(s, i, "<uint>", 0, 6); } constexpr bool is_float(const_str s, unsigned i) { return is_equ_n(s, i, "<float>", 0, 7) || is_equ_n(s, i, "<double>", 0, 8); } constexpr bool is_str(const_str s, unsigned i) { return is_equ_n(s, i, "<str>", 0, 5) || is_equ_n(s, i, "<string>", 0, 8); } constexpr bool is_path(const_str s, unsigned i) { return is_equ_n(s, i, "<path>", 0, 6); }
#endif
 template <typename T> struct parameter_tag { static const int value = 0; };
#define INTERNAL_PARAMETER_TAG(t, i) template <> struct parameter_tag<t> {  static const int value = i; }

 INTERNAL_PARAMETER_TAG(int, 1); INTERNAL_PARAMETER_TAG(char, 1); INTERNAL_PARAMETER_TAG(short, 1); INTERNAL_PARAMETER_TAG(long, 1); INTERNAL_PARAMETER_TAG(long long, 1); INTERNAL_PARAMETER_TAG(unsigned int, 2); INTERNAL_PARAMETER_TAG(unsigned char, 2); INTERNAL_PARAMETER_TAG(unsigned short, 2); INTERNAL_PARAMETER_TAG(unsigned long, 2); INTERNAL_PARAMETER_TAG(unsigned long long, 2); INTERNAL_PARAMETER_TAG(double, 3); INTERNAL_PARAMETER_TAG(std::string, 4);
#undef INTERNAL_PARAMETER_TAG
 template <typename ... Args> struct compute_parameter_tag_from_args_list; template <> struct compute_parameter_tag_from_args_list<> { static const int value = 0; }; template <typename Arg, typename ... Args> struct compute_parameter_tag_from_args_list<Arg, Args...> { static const int sub_value = compute_parameter_tag_from_args_list<Args...>::value; static const int value = parameter_tag<typename std::decay<Arg>::type>::value ? sub_value * 6 + parameter_tag<typename std::decay<Arg>::type>::value : sub_value; }; static inline bool is_parameter_tag_compatible(uint64_t a, uint64_t b) { if (a == 0) return b == 0; if (b == 0) return a == 0; int sa = a % 6; int sb = a % 6; if (sa == 5) sa = 4; if (sb == 5) sb = 4; if (sa != sb) return false; return is_parameter_tag_compatible(a / 6, b / 6); } static inline unsigned find_closing_tag_runtime(const char* s, unsigned p) { return s[p] == 0 ? throw std::runtime_error("unmatched tag <") : s[p] == '>' ? p : find_closing_tag_runtime(s, p + 1); } static inline uint64_t get_parameter_tag_runtime(const char* s, unsigned p = 0) { return s[p] == 0 ? 0 : s[p] == '<' ? ( std::strncmp(s + p, "<int>", 5) == 0 ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 1 : std::strncmp(s + p, "<uint>", 6) == 0 ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 2 : (std::strncmp(s + p, "<float>", 7) == 0 || std::strncmp(s + p, "<double>", 8) == 0) ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 3 : (std::strncmp(s + p, "<str>", 5) == 0 || std::strncmp(s + p, "<string>", 8) == 0) ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 4 : std::strncmp(s + p, "<path>", 6) == 0 ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 5 : throw std::runtime_error("invalid parameter type") ) : get_parameter_tag_runtime(s, p + 1); }
#ifndef MSVC_WORKAROUND
 constexpr uint64_t get_parameter_tag(const_str s, unsigned p = 0) { return p == s.size() ? 0 : s[p] == '<' ? ( is_int(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 1 : is_uint(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 2 : is_float(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 3 : is_str(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 4 : is_path(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 5 : throw std::runtime_error("invalid parameter type") ) : get_parameter_tag(s, p + 1); }
#endif
 template <typename ... T> struct S { template <typename U> using push = S<U, T...>; template <typename U> using push_back = S<T..., U>; template <template<typename ... Args> class U> using rebind = U<T...>; }; template <typename F, typename Set> struct CallHelper; template <typename F, typename ...Args> struct CallHelper<F, S<Args...>> { template <typename F1, typename ...Args1, typename = decltype(std::declval<F1>()(std::declval<Args1>()...)) > static char __test(int); template <typename ...> static int __test(...); static constexpr bool value = sizeof(__test<F, Args...>(0)) == sizeof(char); }; template <int N> struct single_tag_to_type {}; template <> struct single_tag_to_type<1> { using type = int64_t; }; template <> struct single_tag_to_type<2> { using type = uint64_t; }; template <> struct single_tag_to_type<3> { using type = double; }; template <> struct single_tag_to_type<4> { using type = std::string; }; template <> struct single_tag_to_type<5> { using type = std::string; }; template <uint64_t Tag> struct arguments { using subarguments = typename arguments<Tag / 6>::type; using type = typename subarguments::template push<typename single_tag_to_type<Tag % 6>::type>; }; template <> struct arguments<0> { using type = S<>; }; template <typename ... T> struct last_element_type { using type = typename std::tuple_element<sizeof...(T) - 1, std::tuple<T...>>::type; }; template <> struct last_element_type<> {};  template<class T> using Invoke = typename T::type; template<unsigned...> struct seq { using type = seq; }; template<class S1, class S2> struct concat; template<unsigned... I1, unsigned... I2> struct concat<seq<I1...>, seq<I2...>> : seq<I1..., (sizeof...(I1) + I2)...> {}; template<class S1, class S2> using Concat = Invoke<concat<S1, S2>>; template<unsigned N> struct gen_seq; template<unsigned N> using GenSeq = Invoke<gen_seq<N>>; template<unsigned N> struct gen_seq : Concat<GenSeq<N / 2>, GenSeq<N - N / 2>> {}; template<> struct gen_seq<0> : seq<> {}; template<> struct gen_seq<1> : seq<0> {}; template <typename Seq, typename Tuple> struct pop_back_helper; template <unsigned ... N, typename Tuple> struct pop_back_helper<seq<N...>, Tuple> { template <template <typename ... Args> class U> using rebind = U<typename std::tuple_element<N, Tuple>::type...>; }; template <typename ... T> struct pop_back  { template <template <typename ... Args> class U> using rebind = typename pop_back_helper<typename gen_seq<sizeof...(T) - 1>::type, std::tuple<T...>>::template rebind<U>; }; template <> struct pop_back<> { template <template <typename ... Args> class U> using rebind = U<>; };  template < typename Tp, typename... List > struct contains : std::true_type {}; template < typename Tp, typename Head, typename... Rest > struct contains<Tp, Head, Rest...> : std::conditional< std::is_same<Tp, Head>::value, std::true_type, contains<Tp, Rest...> >::type {}; template < typename Tp > struct contains<Tp> : std::false_type {}; template <typename T> struct empty_context {}; template <typename T> struct promote { using type = T; };
#define INTERNAL_PROMOTE_TYPE(t1, t2)  template<>  struct promote<t1>  {  using type = t2;  }

 INTERNAL_PROMOTE_TYPE(char, int64_t); INTERNAL_PROMOTE_TYPE(short, int64_t); INTERNAL_PROMOTE_TYPE(int, int64_t); INTERNAL_PROMOTE_TYPE(long, int64_t); INTERNAL_PROMOTE_TYPE(long long, int64_t); INTERNAL_PROMOTE_TYPE(unsigned char, uint64_t); INTERNAL_PROMOTE_TYPE(unsigned short, uint64_t); INTERNAL_PROMOTE_TYPE(unsigned int, uint64_t); INTERNAL_PROMOTE_TYPE(unsigned long, uint64_t); INTERNAL_PROMOTE_TYPE(unsigned long long, uint64_t); INTERNAL_PROMOTE_TYPE(float, double);
#undef INTERNAL_PROMOTE_TYPE
 template <typename T> using promote_t = typename promote<T>::type; }  namespace detail { template <class T, std::size_t N, class... Args> struct get_index_of_element_from_tuple_by_type_impl { static constexpr auto value = N; }; template <class T, std::size_t N, class... Args> struct get_index_of_element_from_tuple_by_type_impl<T, N, T, Args...> { static constexpr auto value = N; }; template <class T, std::size_t N, class U, class... Args> struct get_index_of_element_from_tuple_by_type_impl<T, N, U, Args...> { static constexpr auto value = get_index_of_element_from_tuple_by_type_impl<T, N + 1, Args...>::value; }; }  namespace utility { template <class T, class... Args> T& get_element_by_type(std::tuple<Args...>& t) { return std::get<detail::get_index_of_element_from_tuple_by_type_impl<T, 0, Args...>::value>(t); } template<typename T> struct function_traits;
#ifndef MSVC_WORKAROUND
 template<typename T> struct function_traits : public function_traits<decltype(&T::operator())> { using parent_t = function_traits<decltype(&T::operator())>; static const size_t arity = parent_t::arity; using result_type = typename parent_t::result_type; template <size_t i> using arg = typename parent_t::template arg<i>; };
#endif
 template<typename ClassType, typename R, typename ...Args> struct function_traits<R(ClassType::*)(Args...) const> { static const size_t arity = sizeof...(Args); typedef R result_type; template <size_t i> using arg = typename std::tuple_element<i, std::tuple<Args...>>::type; }; template<typename ClassType, typename R, typename ...Args> struct function_traits<R(ClassType::*)(Args...)> { static const size_t arity = sizeof...(Args); typedef R result_type; template <size_t i> using arg = typename std::tuple_element<i, std::tuple<Args...>>::type; }; template<typename R, typename ...Args> struct function_traits<std::function<R(Args...)>> { static const size_t arity = sizeof...(Args); typedef R result_type; template <size_t i> using arg = typename std::tuple_element<i, std::tuple<Args...>>::type; }; inline static std::string base64encode(const char* data, size_t size, const char* key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") { std::string ret; ret.resize((size + 2) / 3 * 4); auto it = ret.begin(); while (size >= 3) { *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2]; unsigned char h = (static_cast<unsigned char>(*data++) & 0x03) << 4; *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xF0) >> 4)]; h = (static_cast<unsigned char>(*data++) & 0x0F) << 2; *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xC0) >> 6)]; *it++ = key[static_cast<unsigned char>(*data++) & 0x3F]; size -= 3; } if (size == 1) { *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2]; unsigned char h = (static_cast<unsigned char>(*data++) & 0x03) << 4; *it++ = key[h]; *it++ = '='; *it++ = '='; } else if (size == 2) { *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2]; unsigned char h = (static_cast<unsigned char>(*data++) & 0x03) << 4; *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xF0) >> 4)]; h = (static_cast<unsigned char>(*data++) & 0x0F) << 2; *it++ = key[h]; *it++ = '='; } return ret; } inline static std::string base64encode_urlsafe(const char* data, size_t size) { return base64encode(data, size, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"); } } }